%option yylineno
%{
#include "ts2006.h"
#include "y.tab.h"
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>


#define  MAX_LENG_TOKEN  128 


typedef enum {FALSE=0,TRUE=1} t_booleano;

typedef struct{
	int tipo;
   char   valor[MAX_LENG_TOKEN];
} t_token;


struct ident{
  char nombre[128];
  char tipo[128];
  struct ident *next;
};

struct ident tidentif;


typedef enum {DECLARACION_FUNCIONES, DECLARACION_PARAMETROS,
      DECLARACION_VARIABLES, SENTENCIAS} t_fase;

static int tabla_creada=0;
int procesa_lexico(int);
int tabla_simbolos;
static int tabla_palabras_clave;
int tipo;
%}

letra                               [a-zA-Z]
digito                              [0-9]
signo                               [+-]
blancos                             [ \t\r]*
numeros                             [0-9]+
eol                                 [\r\n]
menos_terminador                    [^,;) \t\n\r]
menos_comilla                       [^\"]
del_c_entera                        [^0-9; .\n\t\r\)+]
del_string                          [^ ;\r\n\),]
del_identificador                   [^0-9a-zA-Z;:,() \n\t\r]
c_entera_error_2_guiones            {digito}(((_{digito})*|digito)*__)+({digito}|_)*
c_entera_error_general              {digito}((_{digito})*|{digito})*({del_c_entera})+
c_entera                            {digito}((_{digito})*|{digito})*
t_entero_error                      [-]?{digito}+({del_c_entera})+({menos_terminador})*
identificador_error_general         {letra}((({letra}|{digito})*)(_({letra}|{digito}))*)*({del_identificador})+
identificador_error_guiones         {letra}((({letra}|{digito})*)(_(_)+({letra}|{digito}))+)+(_|({letra}|{digito})*)*
guiones_error                       _(.)*
comentario                          --(.)+{eol}
identificador                       {letra}((({letra}|{digito})*)(_({letra}|{digito}))*)*
t_entero                            [-]?{digito}+
string_sin_cerrar                   \"({menos_comilla})*{eol}
string_error                        \"({menos_comilla})*\"({del_string})+
string                              \"({menos_comilla})*\"
   
/*otherch                       .*/

%%


{identificador}                     { 
                                      tipo=procesa_lexico(IDENTIF);
                                      return tipo;
                                    }
{c_entera}                          {
	                                   tipo=procesa_lexico(C_ENTERA);
                                      return tipo;
                                    }
{t_entero}                          { 
                                      tipo=procesa_lexico(T_ENTERO);
                                      return tipo;
                                    }
:=                                  { 
                                      tipo=procesa_lexico(OP_ASIGNACION);
                                      return tipo;
                                    }
{identificador_error_guiones}       { 
                                      tipo=procesa_lexico(IDENTIF_ERROR_GUIONES);
                                      return tipo;
                                    }
{identificador_error_general}       {
                                      tipo=procesa_lexico(IDENTIF_ERROR_GENERAL);
                                      return tipo;
                                    }
{c_entera_error_2_guiones}          {
	                                   tipo=procesa_lexico(C_ENTERA_ERROR_2_GUIONES);
                                      return tipo;
                                    }
{c_entera_error_general}            {
	                                   tipo=procesa_lexico(C_ENTERA_ERROR_GENERAL);
                                      return tipo;
                                    }
{t_entero_error}                    {
                                      tipo=procesa_lexico(T_ENTERO_ERROR);                           
                                      return tipo;
                                    }
{blancos}                           { }
{comentario}                        {
                                      tipo=procesa_lexico(COMENTARIO);
                             
                                    }
{string_error}                      {
                                      tipo=procesa_lexico(STRING_ERROR);
                                      return tipo;
                                    }
{string_sin_cerrar}                 {
                                      tipo=procesa_lexico(STRING_SIN_CERRAR);
                                      return tipo;
                                    }
{string}                            {
                                      tipo=procesa_lexico(STRING);
                                      return tipo;
                                    }
\n                                  {
                                      tipo=procesa_lexico(SALTO_LINEA);
                                    }
:                                   {
                                      tipo=procesa_lexico(OP_TIPO);
                                      return tipo;
                                    }
;                                   {
                                      tipo=procesa_lexico(OP_DELIMITADOR);
                                      return tipo;
                                    }
\+                                  {
                                      tipo=procesa_lexico(OP_ARIT_SUMAR);
                                      return tipo;
                                    }
\.                                  {
                                      tipo=procesa_lexico(PUNTO);
                                      return tipo;
                                    }
\(                                  {
                                      tipo=procesa_lexico(ABRE_PARENTESIS);
                                      return tipo;
                                    }
\)                                  {
                                      tipo=procesa_lexico(CIERRA_PARENTESIS);
                                      return tipo;
                                    }
,                                   {
                                      tipo=procesa_lexico(COMA);
                                      return tipo;
                                    }
>                                   {
                                      tipo=procesa_lexico(OP_RELACIONAL);
                                      return tipo;
                                    }
=	                                 {
	                                    tipo=procesa_lexico(IGUAL);
													return tipo;
                                    }
                                    
.                                   { 
                                      tipo=procesa_lexico(ERROR);
                                      return tipo;
                                    }




%%

void minusculizar (char *palabra){
	 short int i;
	 
	 for (i=0; palabra[i];i++)
		  palabra[i] = tolower(palabra[i]);
}

int devuelve_tipo(char *palabra) {
	 int tipo;

	 if (strcmp(palabra, "integer")==0) tipo = INTEGER_PR;
	 else  if (strcmp(palabra, "natural")==0) tipo = NATURAL_PR;
	 else  if (strcmp(palabra, "string")==0) tipo = STRING_PR;
	 else  if (strcmp(palabra, "procedure")==0) tipo = PROCEDURE_PR;
	 else  if (strcmp(palabra, "in")==0) tipo = IN_PR;
	 else  if (strcmp(palabra, "out")==0) tipo = OUT_PR;
	 else  if (strcmp(palabra, "is")==0) tipo = IS_PR;
	 else  if (strcmp(palabra, "begin")==0) tipo = BEGIN_PR;
	 else  if (strcmp(palabra, "end")==0) tipo = END_PR;
	 else  if (strcmp(palabra, "array")==0) tipo = ARRAY_PR;
	 else  if (strcmp(palabra, "of")==0) tipo = OF_PR;
	 else  if (strcmp(palabra, "true")==0) tipo = TRUE_PR;
	 else  if (strcmp(palabra, "false")==0) tipo = FALSE_PR;
	 else  if (strcmp(palabra, "package")==0) tipo = PACKAGE_PR;
	 else  if (strcmp(palabra, "body")==0) tipo = BODY_PR;
	 else  if (strcmp(palabra, "boolean")==0) tipo = BOOLEAN_PR;
	 else  if (strcmp(palabra, "type")==0) tipo = TYPE_PR;
	 else  if (strcmp(palabra, "if")==0) tipo = IF_PR;
	 else  if (strcmp(palabra, "return")==0) tipo = RETURN_PR;
	 else  if (strcmp(palabra, "else")==0) tipo = ELSE_PR;
	 else  if (strcmp(palabra, "then")==0) tipo = THEN_PR;
	 else  if (strcmp(palabra, "and")==0) tipo = AND_PR;
	 return tipo;
}
	 



int inicializa_palabras_clave()
{
	 
	 if((tabla_palabras_clave=crear_tabla())==-1) {
		  fprintf(stdout,"Error en la creacion de las palabras clave\n");
		  exit(-1);
	 }
	 
	 if(crear_entrada(tabla_palabras_clave, "integer")==-1) {
		  fprintf(stdout,"Error insertando integer como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if(crear_entrada(tabla_palabras_clave, "natural")==-1) {
		  fprintf(stdout,"Error insertando natural como una palabra clave\n");
		  exit(-1);
	 }
	 if(crear_entrada(tabla_palabras_clave, "string")==-1) {
		  fprintf(stdout,"Error insertando string como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if(crear_entrada(tabla_palabras_clave, "procedure")==-1) {
		  fprintf(stdout,"Error insertando procedure como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if(crear_entrada(tabla_palabras_clave, "in")==-1) {
		  fprintf(stdout,"Error insertando in como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "out")==-1) {
		  fprintf(stdout,"Error insertando out como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "in out")==-1) {
		  fprintf(stdout,"Error insertando out como una palabra clave\n");
		  exit(-1);
	 }   
	 
	 if (crear_entrada(tabla_palabras_clave, "is")==-1) {
		  fprintf(stdout,"Error insertando is como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "begin")==-1) {
		  fprintf(stdout,"Error insertando begin como una palabra clave\n");
		  exit(-1);
	 }
	 
	 
	 if (crear_entrada(tabla_palabras_clave, "end")==-1) {
		  fprintf(stdout,"Error insertando end como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "array")==-1) {
		  fprintf(stdout,"Error insertando array como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "of")==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "true")==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "false")==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "and")==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "package")==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "body") ==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "boolean") ==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }
	 
	 if (crear_entrada(tabla_palabras_clave, "type") ==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }   

	 if (crear_entrada(tabla_palabras_clave, "return") ==-1) {
		  fprintf(stdout,"Error insertando of como una palabra clave\n");
		  exit(-1);
	 }   

	 if (crear_entrada(tabla_palabras_clave, "then") ==-1) {
		  fprintf(stdout,"Error insertando then como una palabra clave\n");
		  exit(-1);
	 }   

	 if (crear_entrada(tabla_palabras_clave, "if") ==-1) {
		  fprintf(stdout,"Error insertando if como una palabra clave\n");
		  exit(-1);
	 }   

	 if (crear_entrada(tabla_palabras_clave, "else") ==-1) {
		  fprintf(stdout,"Error insertando else como una palabra clave\n");
		  exit(-1);
	 }   
	 
	 return tabla_palabras_clave;
}


int inserta_ts(int id, char *lexema) {   
	 short int va_bien;
	 char * lexema_aux = NULL;
	 size_t longitud;
	 
	 longitud = strlen(lexema);
	 
	 lexema_aux = malloc((longitud + 1)*sizeof(char));
	 memset (lexema_aux, 0, longitud+1*sizeof(char));
	 strncpy(lexema_aux, lexema, longitud);
	 
	 va_bien = existe_entrada (id, lexema_aux);
	 if (va_bien == 1) {
		  va_bien = crear_entrada (id, lexema_aux);
		  if (va_bien == -1) {
				fprintf(stdout,"Error insertando en la tabla %d identificador de lexema %s\n",
						  id, lexema);
				exit(-1);
		  }
		  va_bien = asignar_tipo_entrada(id, lexema, "identificador");
		  if (va_bien == -1) {
				fprintf(stdout,"Error asignando en la tabla %d el lexema identificador %s\n",
						  id, lexema);
				exit(-1);
		  }
		  return (0);  //  Va bien
	 } else {
		  return (-1);  // Ya existia
	 } 
}


int  procesa_lexico(int tipo_token) {
	 extern FILE* salida;
	 t_token token_actual;
	 int entero_tmp = 0;
	 char valor_tmp[MAX_LENG_TOKEN];
	 int i;
	 

	 
    //  Inicializamos el token 
	 memset (&token_actual.valor, 0, MAX_LENG_TOKEN*sizeof(char));
	 minusculizar(yytext);  //  quiero token no el tipo
	 switch(tipo_token){
		  case IDENTIF_ERROR_GUIONES:
				fprintf(salida,"IDENTIF_ERROR_GUIONES:  en la linea %d, en el identificador %s ",
						  yylineno, yytext);
				token_actual.tipo = IDENTIF_ERROR_GUIONES;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case IDENTIF_ERROR_GENERAL:
				fprintf(salida,"IDENTIF_ERROR_GENERAL: en la linea %d, en el identificador %s ",
						  yylineno, yytext);
				token_actual.tipo = IDENTIF_ERROR_GENERAL;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case C_ENTERA_ERROR_2_GUIONES:
				fprintf(salida,"C_ENTERA_ERROR_2_GUIONES: en la linea %d, en el numero %s ",
						  yylineno, yytext);
				token_actual.tipo = C_ENTERA_ERROR_2_GUIONES;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case C_ENTERA_ERROR_GENERAL:
				fprintf(salida,"C_ENTERA_ERROR_GENERAL: en la linea %d, en el numero %s ",
						  yylineno, yytext);
				token_actual.tipo = C_ENTERA_ERROR_GENERAL;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case T_ENTERO_ERROR:
				fprintf(salida,"TIPO_ENTERO_ERROR: en la linea %d, en el numero %s ",
						  yylineno, yytext);
				token_actual.tipo = T_ENTERO_ERROR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case IDENTIF:
				if(existe_entrada(tabla_palabras_clave,yytext)==0) {
					 fprintf(salida,"Palabra reservada: %s ", yytext);
					 //token_actual.tipo = PALABRA_RESERVADA;
					 //Cambio. Se pasa la palabra reservada para que no de tantos errores el sintactico
					 //Le pego _PR al fina por problemas con redefiniciones
					 token_actual.tipo = devuelve_tipo(yytext);
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);     
				} else {
					 fprintf(salida,"Identificador: %s ", yytext);
					 token_actual.tipo = IDENTIF;
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
					 //inserta_ts(tabla_simbolos, token_actual.valor);
				}
				// Se copia en yylval el token para pasarselo a bison
				//memset(&tidentif,0,sizeof(tidentif));         
				//strncpy(tidentif.nombre, yytext, MAX_LENG_TOKEN);
				strncpy(yylval.cadena, yytext, MAX_LENG_TOKEN);
				break;
		  case C_ENTERA:
				for (i=0; yytext[i]; i++)
					 if ((yytext[i] >= '0') && (yytext[i] <= '9'))
					 {
						  entero_tmp = entero_tmp * 10 + (int)(yytext[i] - '0');
					 }
				if (entero_tmp <= 32767) {
					 fprintf(salida,"Constante Entera: %d ", entero_tmp);
					 token_actual.tipo = C_ENTERA;
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
					 yylval.numero = entero_tmp;
				}
				else {
					 fprintf(salida,"ENTERO_ERROR_GRANDE: entero muy grande %d ", entero_tmp);
					 token_actual.tipo = ENTERO_ERROR_GRANDE;
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				}
				i = 0;
				break;
		  case T_ENTERO:
				entero_tmp = 0;
				entero_tmp = atoi(yytext);
				if (entero_tmp <= 32767) {
					 fprintf(salida,"Tipo Entero: %d ", entero_tmp);
					 token_actual.tipo = T_ENTERO;
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
					 yylval.numero = atoi(yytext);
				}
				else {
					 fprintf(salida,"ENTERO_ERROR_GRANDE: entero muy grande %d ", entero_tmp);
					 token_actual.tipo = ENTERO_ERROR_GRANDE;
					 strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				}
				break;
		  case COMENTARIO:
				/*fprintf(salida,"COMENTARIO ");*/
				token_actual.tipo = COMENTARIO;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case SALTO_LINEA:
				fprintf(salida,"\n");
				token_actual.tipo = SALTO_LINEA;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case OP_ASIGNACION:
				fprintf(salida,"OP_ASIGNACION: %s ", yytext);
				token_actual.tipo = OP_ASIGNACION;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case OP_TIPO:
				fprintf(salida,"OP_TIPO: %s ", yytext);
				token_actual.tipo = OP_TIPO;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case OP_DELIMITADOR:
				fprintf(salida,"OP_DELIMITADOR: %s ", yytext);
				token_actual.tipo = OP_DELIMITADOR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case OP_ARIT_SUMAR:
				fprintf(salida,"Operacion aritmetica sumar: %s ", yytext);
				token_actual.tipo = OP_ARIT_SUMAR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case PUNTO:
				fprintf(salida,"Punto: %s ", yytext);
				token_actual.tipo = PUNTO;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case STRING:
				i = strlen (yytext);
				memset (&valor_tmp, 0, MAX_LENG_TOKEN*sizeof(char));
				strncpy (valor_tmp, (yytext + sizeof(char)), i - 2);
				fprintf(salida,"STRING: %s ", valor_tmp);
				token_actual.tipo = STRING;
				strncpy(token_actual.valor, valor_tmp, MAX_LENG_TOKEN);
				strncpy(yylval.cadena, valor_tmp, MAX_LENG_TOKEN);
				break;  
		  case STRING_SIN_CERRAR:
				fprintf(salida,"STRING_ERROR_SIN_CERRAR en la linea %d, en el string: %s ",
						  yylineno, yytext);
				token_actual.tipo = STRING_SIN_CERRAR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case STRING_ERROR:
				fprintf(salida,"STRING_ERROR en la linea %d, en el string: %s ",
						  yylineno, yytext);
				token_actual.tipo = STRING_ERROR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case ABRE_PARENTESIS:
				fprintf(salida,"ABRE_PARENTESIS: el simbolo %s ", yytext);
				token_actual.tipo = ABRE_PARENTESIS;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case CIERRA_PARENTESIS:
				fprintf(salida,"CIERRA_PARENTESIS: el simbolo %s ", yytext);
				token_actual.tipo = CIERRA_PARENTESIS;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case COMA:
				fprintf(salida,"COMA: el simbolo %s ", yytext);
				token_actual.tipo = COMA;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case IGUAL:
				fprintf(salida,"IGUAL: el simbolo %s ", yytext);
				token_actual.tipo = IGUAL;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case OP_RELACIONAL:
				fprintf(salida,"OP_RELACIONAL: el simbolo %s ", yytext);
				token_actual.tipo = OP_RELACIONAL;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
		  case ERROR:
				fprintf(salida,"ERROR en la linea %d, token \"%s\" no reconocido\n",
						  yylineno, yytext);
				token_actual.tipo = ERROR;
				strncpy(token_actual.valor, yytext, MAX_LENG_TOKEN);
				break;
				/*yyterminate();*/
	 }
    return token_actual.tipo;
	 
}
